Skip to content

RUMS-6014: Fix missing text boxes with mask none#1305

Merged
jonathanmos merged 1 commit into
developfrom
jmoskovich/rums-6014/svg-privacy-issue
Jun 15, 2026
Merged

RUMS-6014: Fix missing text boxes with mask none#1305
jonathanmos merged 1 commit into
developfrom
jmoskovich/rums-6014/svg-privacy-issue

Conversation

@jonathanmos

Copy link
Copy Markdown
Member

What does this PR do?

Problem
On Android, any content placed inside SessionReplayView.MaskNone, SessionReplayView.MaskAll, or SessionReplayView.Hide was completely absent from Session Replay recordings. iOS captured the same content correctly under identical configuration.

Root cause
DdPrivacyView — the Android native backing view for all SessionReplayView variants — was registered with SvgViewMapper. That mapper was originally written to handle a separate use case: rendering inline SVGs via the Datadog babel plugin, where DdPrivacyView carries SVG binary data in its attributes map.

When DdPrivacyView is used as a privacy wrapper (no SVG attributes), two things went wrong:

SvgViewMapper.map() returned an empty wireframe list immediately, so the wrapper container itself never appeared in the recording.
SvgViewMapper did not implement TraverseAllChildrenMapper, so the Session Replay framework never descended into the wrapper's children regardless of what the mapper returned.

Fix
SvgViewMapper now implements TraverseAllChildrenMapper, which tells the SR framework to traverse the children of any DdPrivacyView it handles.
When DdPrivacyView has no hash attribute (privacy-wrapper mode), map() now returns a ShapeWireframe for the container instead of an empty list.
The type bound was tightened from T : View to T : ViewGroup, required by the TraverseAllChildrenMapper interface.
The SVG path also has a latent fix: ImageWireframe now uses viewIdentifierResolver.resolveChildUniqueIdentifier(view, "svg") for its ID instead of resolveViewId(subView). With TraverseAllChildrenMapper in place the framework independently traverses the SVG child view, which would produce a second wireframe with the same resolveViewId(subView) ID — overwriting the image in the recording.
Testing
Added SvgViewMapperTest covering the privacy-wrapper path, the SVG path, and the ID uniqueness invariant.
Manually verified on Android: MaskNone content is visible and unmasked, MaskAll content is visible and masked (text rendered as x's), Hide wrapper is absent from the recording.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)
  • If this PR is auto-generated, please make sure also to manually update the code related to the change

@jonathanmos jonathanmos marked this pull request as ready for review June 15, 2026 08:18
@jonathanmos jonathanmos requested a review from a team as a code owner June 15, 2026 08:18
Copilot AI review requested due to automatic review settings June 15, 2026 08:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an Android Session Replay mapping issue where DdPrivacyView (used by SessionReplayView.MaskNone/MaskAll/Hide) prevented the Session Replay framework from traversing and recording its child views, causing wrapped content to be missing from recordings.

Changes:

  • Updated SvgViewMapper to implement TraverseAllChildrenMapper and tightened its generic bound to T : ViewGroup so the SR framework traverses DdPrivacyView children.
  • Adjusted SvgViewMapper.map() to return a container ShapeWireframe when DdPrivacyView is used as a privacy wrapper (no SVG hash attribute), instead of returning an empty list.
  • Ensured SVG ImageWireframe IDs don’t collide with independently-traversed child views by using resolveChildUniqueIdentifier(view, "svg"), and added unit tests covering these scenarios.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/SvgViewMapper.kt Enables child traversal for DdPrivacyView, maps privacy-wrapper containers as shapes, and avoids SVG wireframe ID collisions.
packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/SvgViewMapperTest.kt Adds test coverage for privacy-wrapper behavior, SVG behavior, and the ID uniqueness invariant.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jonathanmos jonathanmos merged commit 76dae77 into develop Jun 15, 2026
12 checks passed
@jonathanmos jonathanmos deleted the jmoskovich/rums-6014/svg-privacy-issue branch June 15, 2026 12:20
@sbarrio sbarrio mentioned this pull request Jun 15, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants